////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                                            //
//                                                         WNProject                                                          //
//                                                                                                                            //
//            This file is distributed under the BSD 2-Clause open source license. See License.txt for details.               //
//                                                                                                                            //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#pragma once

#ifndef __WN_CONCURRENCY_READ_WRITE_MUTEX_INL__
#define __WN_CONCURRENCY_READ_WRITE_MUTEX_INL__

#include "WNCore/inc/WNAssert.h"

#ifdef _WN_WINDOWS
    #include <windows.h>
#elif defined _WN_LINUX
    #include <pthread.h>
#endif

namespace WNConcurrency {
    WN_FORCE_INLINE WNReadWriteMutex::WNReadWriteMutex() {
        #ifdef _WN_WINDOWS
            InitializeSRWLock(&mSlimReadWriteLock);
        #elif defined _WN_LINUX
            WN_RELEASE_ASSERT(pthread_rwlock_init(&mReadWriteLock, NULL) == 0);
        #endif
    }

    WN_FORCE_INLINE WNReadWriteMutex::~WNReadWriteMutex() {
        #ifdef _WN_LINUX
            pthread_rwlock_destroy(&mReadWriteLock);
        #endif
    }

    WN_FORCE_INLINE WN_VOID WNReadWriteMutex::LockReader() {
        #ifdef _WN_WINDOWS
            AcquireSRWLockShared(&mSlimReadWriteLock);
        #elif defined _WN_LINUX
            WN_RELEASE_ASSERT(pthread_rwlock_rdlock(&mReadWriteLock, NULL) == 0);
        #endif
    }

    WN_FORCE_INLINE WN_BOOL WNReadWriteMutex::TryLockReader() {
        #ifdef _WN_WINDOWS
            return(TryAcquireSRWLockShared(&mSlimReadWriteLock) == TRUE);
        #elif defined _WN_LINUX
            return(pthread_rwlock_tryrdlock(&mReadWriteLock) == 0 ? WN_TRUE : WN_FALSE);
        #endif
    }

    WN_FORCE_INLINE WN_VOID WNReadWriteMutex::UnlockReader() {
        #ifdef _WN_WINDOWS
            ReleaseSRWLockShared(&mSlimReadWriteLock);
        #elif defined _WN_LINUX
            WN_RELEASE_ASSERT(pthread_rwlock_unlock(&mReadWriteLock, NULL) == 0);
        #endif
    }

    WN_FORCE_INLINE WN_VOID WNReadWriteMutex::LockWriter() {
        #ifdef _WN_WINDOWS
            AcquireSRWLockExclusive(&mSlimReadWriteLock);
        #elif defined _WN_LINUX
            WN_RELEASE_ASSERT(pthread_rwlock_rwlock(&mReadWriteLock, NULL) == 0);
        #endif
    }

    WN_FORCE_INLINE WN_BOOL WNReadWriteMutex::TryLockWriter() {
        #ifdef _WN_WINDOWS
            return(TryAcquireSRWLockExclusive(&mSlimReadWriteLock) == TRUE);
        #elif defined _WN_LINUX
            return(pthread_rwlock_tryrwlock(&mReadWriteLock) == 0 ? WN_TRUE : WN_FALSE);
        #endif
    }

    WN_FORCE_INLINE WN_VOID WNReadWriteMutex::UnlockWriter() {
        #ifdef _WN_WINDOWS
            ReleaseSRWLockExclusive(&mSlimReadWriteLock);
        #elif defined _WN_LINUX
            WN_RELEASE_ASSERT(pthread_rwlock_unlock(&mReadWriteLock, NULL) == 0);
        #endif
    }
}

#endif // __WN_CONCURRENCY_READ_WRITE_MUTEX_INL__